/**
 *  Copyright (c) Filipe Manana <fdmanana@gmail.com>
 *  All rights reserved.
 * 
 *  This file is part of jsdet.
 *
 *  jsdet is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published
 *  by the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  jsdet is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with jsdet.  If not, see <http://www.gnu.org/licenses/>.
 *
 */


package jsdet;

import java.util.*;

import jsdet.arguments.Arguments;
import jsdet.arguments.Option;
import jsdet.exceptions.ParsingException;
import jsdet.parsing.Parser;
import jsdet.parsing.ParsingStats;
import jsdet.parsing.GlobalParsingStats;
import jsdet.parsing.reporting.Reporter;
import jsdet.parsing.reporting.ConsoleReporter;
import jsdet.parsing.reporting.HtmlReporter;
import jsdet.parsing.reporting.HtmlGUIReporter;
import jsdet.parsing.reporting.XmlReporter;


/**
 *
 * @author Filipe Manana
 * 
 */
public class Main {

    private static Arguments arguments = null;

    public static void main(String[] args) throws Exception {

        try {
            arguments = Arguments.parseArguments(args);
        }
        catch (IllegalArgumentException ex) {
            System.err.println(ex.getMessage());
            System.exit(1);
        }

        if (arguments.hasOption(Option.HELP)) {
            showHelp();
            System.exit(0);
        }

        Set<String> files = arguments.getFiles();

        GlobalParsingStats stats = parseFiles(files);

        reportParsingResults(stats);
    }


    private static GlobalParsingStats parseFiles(Set<String> files) {

        GlobalParsingStats globalStats = new GlobalParsingStats();

        for (String file : files) {

            Parser parser = null;

            try {
                if ( file.equals("-") ) {
                    // read from stdin
                    parser = new Parser("-", System.in);
                }
                else {
                    parser = new Parser(file);
                }
            }
            catch (Exception ex) {
                System.err.println("Error while opening file `" + file + "' : " + ex.getMessage());
                continue;
            }

            parser.setDebug(arguments.hasOption(Option.DEBUG));

            try {
                parser.doParsing();
            }
            catch(ParsingException ex) {
                reportParsingErrors(parser, ex);
                System.exit(1);
            }

            ParsingStats stats = parser.getParsingStats();
            globalStats.addParsingStats(stats, parser.getFileName());
        }

        return globalStats;
    }


    private static void reportParsingErrors(Parser parser, ParsingException ex) {
        List<String> errors = parser.getErrors();

        if ( errors == null ) {
            errors = new ArrayList<String>();
            String msg = ex.getMessage();

            if ( msg != null ) {
                errors.add(msg);
            }
        }

        if ( parser.getFileName().equals("-") ) {
            System.err.println("Error(s) found while parsing standard input");
        }
        else {
            System.err.println("Error(s) found while parsing file `" + parser.getFileName() + "'");
        }

        System.err.println();

        for (String error : errors) {
            System.err.println("\t" + error);
        }
    }


    private static void reportParsingResults(GlobalParsingStats stats) {
        Reporter reporter = null;

        if ( arguments.hasOption(Option.SIMPLE_HTML) ) {
            reporter = new HtmlReporter();
        }
        else if ( arguments.hasOption(Option.HTML_GUI) ) {
            reporter = new HtmlGUIReporter();
        }
        else if ( arguments.hasOption(Option.XML) ) {
            reporter = new XmlReporter();
        }
        else {
            reporter = new ConsoleReporter();
        }

        if ( arguments.hasOption(Option.SORT_CLASSES_ASC) ) {
            reporter.setClassesSortOrder(Reporter.ClassesSortOrder.ASC);
        }
        else if ( arguments.hasOption(Option.SORT_CLASSES_DESC) ) {
            reporter.setClassesSortOrder(Reporter.ClassesSortOrder.DESC);
        }

        reporter.setOriginalArgs(arguments.getOriginalArgs());
        reporter.setReportFunctions(arguments.hasOption(Option.SHOW_FUNCTIONS));
        reporter.setReportClosureObjects(arguments.hasOption(Option.SHOW_CLOSURE_OBJECTS));
        reporter.setReportFileNames(arguments.hasOption(Option.SHOW_FILES));
        reporter.setReportNamesOnly(arguments.hasOption(Option.NAMES_ONLY));
        reporter.setReportInheritedMembers(arguments.hasOption(Option.SHOW_INHERITED_MEMBERS));

        if ( arguments.haveClassesForFiltering() ) {
            reporter.setClassesToFilter(arguments.getClasses());
        }

        reporter.reportGlobalParsingStats(stats);
    }


    private static void showHelp() {
        System.out.println();
        System.out.println("Usage:  java -jar jsdet.jar [options]* [JavaScript_file | directory]+");
        System.out.println();
        System.out.println("To read from standard input, use - (single dash) as a file/directory name.");
        System.out.println();
        System.out.println("Options:");
        System.out.println();
        System.out.println("--help, -h");
        System.out.println("\tDisplays this help.");
        System.out.println();
        System.out.println("--debug");
        System.out.println("\tTurn debug mode on.");
        System.out.println();
        System.out.println("--show-inherited-members, -i");
        System.out.println("\tShow classes' inherited members.");
        System.out.println("\tBy default inherited members are omitted from the output.");
        System.out.println();
        System.out.println("--asc");
        System.out.println("\tSort classes, in ascending order, according to their level in the class hierarchy.");
        System.out.println();
        System.out.println("--desc");
        System.out.println("\tSort classes, in descending order, according to their level in the class hierarchy.");
        System.out.println();
        System.out.println("--names-only");
        System.out.println("\tOnly report class names and closure object names.");
        System.out.println("\tInformation about class and closure object members is omitted.");
        System.out.println();
        System.out.println("--show-closure-objects, -o");
        System.out.println("\tReport also the closure objects declared in the global namespace.");
        System.out.println();
        System.out.println("--show-functions, -f");
        System.out.println("\tReport also the functions declared in the global namespace.");
        System.out.println();
        System.out.println("--show-files");
        System.out.println("\tShow the name of the files where class members, closure objects and functions are defined.");
        System.out.println();
        System.out.println("--classes, -c  class1,class2,class3,class4...");
        System.out.println("\tOnly show information regarding the specified classes.");
        System.out.println("\tValue is a comma separated list of class names.");
        System.out.println("\tIf this option is omitted, information about all classes is showed.");
        System.out.println();
        System.out.println("--html");
        System.out.println("\tGenerate simple HTML output.");
        System.out.println();
        System.out.println("--html-gui");
        System.out.println("\tGenerate JavaScript variables for the HTML GUI.");
        System.out.println("\tThis output must then be placed into the HTML GUI root directory as a file named `jsdet-output.js'.");
        System.out.println("\tThe HTML GUI directory is found in the jsdet distribution package as the directory named `html-gui-files'.");
        System.out.println();
        System.out.println("--xml");
        System.out.println("\tGenerate XML output.");
        System.out.println();
    }
}
